﻿using System.IO;
using dnAnalytics.LinearAlgebra;
using dnAnalytics.LinearAlgebra.IO;
using NUnit.Framework;

namespace dnAnalytics.Tests.LinearAlgebra.IO
{
    [TestFixture]
    public class MatrixMarketWriterTest
    {
        [Test]
        public void WriteMatrixStringGeneralArray()
        {
            MatrixMarketReader mmr = new MatrixMarketReader();
            Matrix matrix = mmr.ReadMatrix("./TestData/Matrices/random_real_general_array_10_20.mtx", StorageType.Dense);
            MatrixMarketWriter mmw = new MatrixMarketWriter(ExchangeFormat.Array, DataType.Real);
            mmw.WriteMatrix(matrix, "./TestData/Matrices/temp_string_real_general_array.mtx");

            matrix = mmr.ReadMatrix("./TestData/Matrices/temp_string_real_general_array.mtx", StorageType.Dense);
            Assert.AreEqual(10, matrix.Rows);
            Assert.AreEqual(20, matrix.Columns);
            const double expected = 851.83805;
            double actual = matrix.FrobeniusNorm();
            double error = System.Math.Abs((actual - expected) / expected);
            Assert.IsTrue(error < Constants.IOAcceptableError);
        }

        [Test]
        public void WriteMatrixStringGeneralArrayFormat()
        {
            MatrixMarketReader mmr = new MatrixMarketReader();
            Matrix matrix = mmr.ReadMatrix("./TestData/Matrices/random_real_general_array_10_20.mtx", StorageType.Dense);
            MatrixMarketWriter mmw = new MatrixMarketWriter(ExchangeFormat.Array, DataType.Real);
            mmw.WriteMatrix(matrix, "./TestData/Matrices/temp_string_real_general_array_format.mtx", "E");

            matrix = mmr.ReadMatrix("./TestData/Matrices/temp_string_real_general_array_format.mtx", StorageType.Dense);
            Assert.AreEqual(10, matrix.Rows);
            Assert.AreEqual(20, matrix.Columns);
            const double expected = 851.83805;
            double actual = matrix.FrobeniusNorm();
            double error = System.Math.Abs((actual - expected) / expected);
            Assert.IsTrue(error < Constants.IOAcceptableError);
        }

        [Test]
        public void WriteMatrixStreamGeneralArray()
        {
            MatrixMarketReader mmr = new MatrixMarketReader();
            Matrix matrix = mmr.ReadMatrix(File.OpenRead("./TestData/Matrices/random_real_general_array_10_20.mtx"), StorageType.Dense);
            MatrixMarketWriter mmw = new MatrixMarketWriter(ExchangeFormat.Array, DataType.Real);
            mmw.WriteMatrix(matrix, File.OpenWrite("./TestData/Matrices/temp_stream_real_general_array.mtx"));

            matrix = mmr.ReadMatrix("./TestData/Matrices/temp_stream_real_general_array.mtx", StorageType.Dense);
            Assert.AreEqual(10, matrix.Rows);
            Assert.AreEqual(20, matrix.Columns);
            const double expected = 851.83805;
            double actual = matrix.FrobeniusNorm();
            double error = System.Math.Abs((actual - expected) / expected);
            Assert.IsTrue(error < Constants.IOAcceptableError);
        }

        [Test]
        public void WriteMatrixStreamGeneralArrayFormat()
        {
            MatrixMarketReader mmr = new MatrixMarketReader();
            Matrix matrix = mmr.ReadMatrix(File.OpenRead("./TestData/Matrices/random_real_general_array_10_20.mtx"), StorageType.Dense);
            MatrixMarketWriter mmw = new MatrixMarketWriter(ExchangeFormat.Array, DataType.Real);
            mmw.WriteMatrix(matrix, File.OpenWrite("./TestData/Matrices/temp_stream_real_general_array_format.mtx"), "E");

            matrix = mmr.ReadMatrix("./TestData/Matrices/temp_stream_real_general_array_format.mtx", StorageType.Dense);
            Assert.AreEqual(10, matrix.Rows);
            Assert.AreEqual(20, matrix.Columns);
            const double expected = 851.83805;
            double actual = matrix.FrobeniusNorm();
            double error = System.Math.Abs((actual - expected) / expected);
            Assert.IsTrue(error < Constants.IOAcceptableError);
        }

        [Test]
        public void WriteMatrixTextWriterGeneralArray()
        {
            MatrixMarketReader mmr = new MatrixMarketReader();
            Matrix matrix = mmr.ReadMatrix("./TestData/Matrices/random_real_general_array_10_20.mtx", StorageType.Dense);
            MatrixMarketWriter mmw = new MatrixMarketWriter(ExchangeFormat.Array, DataType.Real);

            using (TextWriter tw = new StreamWriter("./TestData/Matrices/temp_writer_real_general_array.mtx"))
            {
                mmw.WriteMatrix(matrix, tw);
            }

            matrix = mmr.ReadMatrix("./TestData/Matrices/temp_writer_real_general_array.mtx", StorageType.Dense);
            Assert.AreEqual(10, matrix.Rows);
            Assert.AreEqual(20, matrix.Columns);
            const double expected = 851.83805;
            double actual = matrix.FrobeniusNorm();
            double error = System.Math.Abs((actual - expected) / expected);
            Assert.IsTrue(error < Constants.IOAcceptableError);
        }

        [Test]
        public void WriteMatrixTextWriterGeneralArrayFormat()
        {
            MatrixMarketReader mmr = new MatrixMarketReader();
            Matrix matrix = mmr.ReadMatrix("./TestData/Matrices/random_real_general_array_10_20.mtx", StorageType.Dense);
            MatrixMarketWriter mmw = new MatrixMarketWriter(ExchangeFormat.Array, DataType.Real);

            using (TextWriter tw = new StreamWriter("./TestData/Matrices/temp_writer_real_general_array_format.mtx"))
            {
                mmw.WriteMatrix(matrix, tw, "E");
            }

            matrix = mmr.ReadMatrix("./TestData/Matrices/temp_writer_real_general_array_format.mtx", StorageType.Dense);
            Assert.AreEqual(10, matrix.Rows);
            Assert.AreEqual(20, matrix.Columns);
            const double expected = 851.83805;
            double actual = matrix.FrobeniusNorm();
            double error = System.Math.Abs((actual - expected) / expected);
            Assert.IsTrue(error < Constants.IOAcceptableError);
        }

        [Test]
        public void WriteMatrixStringGeneralCoordinate()
        {
            MatrixMarketReader mmr = new MatrixMarketReader();
            Matrix matrix = mmr.ReadMatrix("./TestData/Matrices/random_real_general_coordinate_10_20.mtx", StorageType.Dense);
            MatrixMarketWriter mmw = new MatrixMarketWriter(ExchangeFormat.Coordinate, DataType.Real);
            mmw.WriteMatrix(matrix, "./TestData/Matrices/temp_string_real_general_coordinate.mtx");

            matrix = mmr.ReadMatrix("./TestData/Matrices/temp_string_real_general_coordinate.mtx", StorageType.Dense);
            Assert.AreEqual(10, matrix.Rows);
            Assert.AreEqual(20, matrix.Columns);
            const double expected = 402.0734;
            double actual = matrix.FrobeniusNorm();
            double error = System.Math.Abs((actual - expected) / expected);
            Assert.IsTrue(error < Constants.IOAcceptableError);
        }

        [Test]
        public void WriteMatrixStringGeneralCoordinateFormat()
        {
            MatrixMarketReader mmr = new MatrixMarketReader();
            Matrix matrix = mmr.ReadMatrix("./TestData/Matrices/random_real_general_coordinate_10_20.mtx", StorageType.Dense);
            MatrixMarketWriter mmw = new MatrixMarketWriter(ExchangeFormat.Coordinate, DataType.Real);
            mmw.WriteMatrix(matrix, "./TestData/Matrices/temp_string_real_general_coordinate_format.mtx", "E");

            matrix = mmr.ReadMatrix("./TestData/Matrices/temp_string_real_general_coordinate_format.mtx", StorageType.Dense);
            Assert.AreEqual(10, matrix.Rows);
            Assert.AreEqual(20, matrix.Columns);
            const double expected = 402.0734;
            double actual = matrix.FrobeniusNorm();
            double error = System.Math.Abs((actual - expected) / expected);
            Assert.IsTrue(error < Constants.IOAcceptableError);
        }

        [Test]
        public void WriteMatrixStreamGeneralCoordinate()
        {
            MatrixMarketReader mmr = new MatrixMarketReader();
            Matrix matrix = mmr.ReadMatrix(File.OpenRead("./TestData/Matrices/random_real_general_coordinate_10_20.mtx"), StorageType.Dense);
            MatrixMarketWriter mmw = new MatrixMarketWriter(ExchangeFormat.Coordinate, DataType.Real);
            mmw.WriteMatrix(matrix, File.OpenWrite("./TestData/Matrices/temp_stream_real_general_coordinate.mtx"));

            matrix = mmr.ReadMatrix("./TestData/Matrices/temp_stream_real_general_coordinate.mtx", StorageType.Dense);
            Assert.AreEqual(10, matrix.Rows);
            Assert.AreEqual(20, matrix.Columns);
            const double expected = 402.0734;
            double actual = matrix.FrobeniusNorm();
            double error = System.Math.Abs((actual - expected) / expected);
            Assert.IsTrue(error < Constants.IOAcceptableError);
        }

        [Test]
        public void WriteMatrixStreamGeneralCoordinateFormat()
        {
            MatrixMarketReader mmr = new MatrixMarketReader();
            Matrix matrix = mmr.ReadMatrix(File.OpenRead("./TestData/Matrices/random_real_general_coordinate_10_20.mtx"), StorageType.Dense);
            MatrixMarketWriter mmw = new MatrixMarketWriter(ExchangeFormat.Coordinate, DataType.Real);
            mmw.WriteMatrix(matrix, File.OpenWrite("./TestData/Matrices/temp_stream_real_general_coordinate_format.mtx"), "E");

            matrix = mmr.ReadMatrix("./TestData/Matrices/temp_stream_real_general_coordinate_format.mtx", StorageType.Dense);
            Assert.AreEqual(10, matrix.Rows);
            Assert.AreEqual(20, matrix.Columns);
            const double expected = 402.0734;
            double actual = matrix.FrobeniusNorm();
            double error = System.Math.Abs((actual - expected) / expected);
            Assert.IsTrue(error < Constants.IOAcceptableError);
        }

        [Test]
        public void WriteMatrixTextWriterGeneralCoordinate()
        {
            MatrixMarketReader mmr = new MatrixMarketReader();
            Matrix matrix = mmr.ReadMatrix("./TestData/Matrices/random_real_general_coordinate_10_20.mtx", StorageType.Dense);
            MatrixMarketWriter mmw = new MatrixMarketWriter(ExchangeFormat.Coordinate, DataType.Real);

            using (TextWriter tw = new StreamWriter("./TestData/Matrices/temp_writer_real_general_coordinate.mtx"))
            {
                mmw.WriteMatrix(matrix, tw);
            }

            matrix = mmr.ReadMatrix("./TestData/Matrices/temp_writer_real_general_coordinate.mtx", StorageType.Dense);
            Assert.AreEqual(10, matrix.Rows);
            Assert.AreEqual(20, matrix.Columns);
            const double expected = 402.0734;
            double actual = matrix.FrobeniusNorm();
            double error = System.Math.Abs((actual - expected) / expected);
            Assert.IsTrue(error < Constants.IOAcceptableError);
        }


        [Test]
        public void WriteMatrixTextWriterGeneralCoordinateFormat()
        {
            MatrixMarketReader mmr = new MatrixMarketReader();
            Matrix matrix = mmr.ReadMatrix("./TestData/Matrices/random_real_general_coordinate_10_20.mtx", StorageType.Dense);
            MatrixMarketWriter mmw = new MatrixMarketWriter(ExchangeFormat.Coordinate, DataType.Real);

            using (TextWriter tw = new StreamWriter("./TestData/Matrices/temp_writer_real_general_coordinate_format.mtx"))
            {
                mmw.WriteMatrix(matrix, tw, "E");
            }

            matrix = mmr.ReadMatrix("./TestData/Matrices/temp_writer_real_general_coordinate_format.mtx", StorageType.Dense);
            Assert.AreEqual(10, matrix.Rows);
            Assert.AreEqual(20, matrix.Columns);
            const double expected = 402.0734;
            double actual = matrix.FrobeniusNorm();
            double error = System.Math.Abs((actual - expected) / expected);
            Assert.IsTrue(error < Constants.IOAcceptableError);
        }

        [Test]
        public void WriteMatrixStringPatternSymmetricArray()
        {
            MatrixMarketReader mmr = new MatrixMarketReader();
            Matrix matrix = mmr.ReadMatrix("./TestData/Matrices/can24_pattern_symmetric_coordinate_24.mtx", StorageType.Dense);
            MatrixMarketWriter mmw = new MatrixMarketWriter(ExchangeFormat.Array, DataType.Real);
            mmw.WriteMatrix(matrix, "./TestData/Matrices/temp_string_pattern_symmetric_array.mtx");

            matrix = mmr.ReadMatrix("./TestData/Matrices/temp_string_pattern_symmetric_array.mtx", StorageType.Dense);
            Assert.AreEqual(24, matrix.Rows);
            Assert.AreEqual(24, matrix.Columns);
        }

        [Test]
        public void WriteMatrixStringPatternSymmetricArrayFormat()
        {
            MatrixMarketReader mmr = new MatrixMarketReader();
            Matrix matrix = mmr.ReadMatrix("./TestData/Matrices/can24_pattern_symmetric_coordinate_24.mtx", StorageType.Dense);
            MatrixMarketWriter mmw = new MatrixMarketWriter(ExchangeFormat.Array, DataType.Real);
            mmw.WriteMatrix(matrix, "./TestData/Matrices/temp_string_pattern_symmetric_array_format.mtx", "E");

            matrix = mmr.ReadMatrix("./TestData/Matrices/temp_string_pattern_symmetric_array_format.mtx", StorageType.Dense);
            Assert.AreEqual(24, matrix.Rows);
            Assert.AreEqual(24, matrix.Columns);
        }

        [Test]
        public void WriteMatrixStreamPatternSymmetricArray()
        {
            MatrixMarketReader mmr = new MatrixMarketReader();
            Matrix matrix = mmr.ReadMatrix(File.OpenRead("./TestData/Matrices/can24_pattern_symmetric_coordinate_24.mtx"), StorageType.Dense);
            MatrixMarketWriter mmw = new MatrixMarketWriter(ExchangeFormat.Array, DataType.Real);
            mmw.WriteMatrix(matrix, File.OpenWrite("./TestData/Matrices/temp_stream_pattern_symmetric_array.mtx"));

            matrix = mmr.ReadMatrix("./TestData/Matrices/temp_stream_pattern_symmetric_array.mtx", StorageType.Dense);
            Assert.AreEqual(24, matrix.Rows);
            Assert.AreEqual(24, matrix.Columns);
        }

        [Test]
        public void WriteMatrixStreamPatternSymmetricArrayFormat()
        {
            MatrixMarketReader mmr = new MatrixMarketReader();
            Matrix matrix = mmr.ReadMatrix(File.OpenRead("./TestData/Matrices/can24_pattern_symmetric_coordinate_24.mtx"), StorageType.Dense);
            MatrixMarketWriter mmw = new MatrixMarketWriter(ExchangeFormat.Array, DataType.Real);
            mmw.WriteMatrix(matrix, File.OpenWrite("./TestData/Matrices/temp_stream_pattern_symmetric_array_format.mtx"), "E");

            matrix = mmr.ReadMatrix("./TestData/Matrices/temp_stream_pattern_symmetric_array_format.mtx", StorageType.Dense);
            Assert.AreEqual(24, matrix.Rows);
            Assert.AreEqual(24, matrix.Columns);
        }

        [Test]
        public void WriteMatrixTextReaderPatternSymmetricArray()
        {
            MatrixMarketReader mmr = new MatrixMarketReader();
            Matrix matrix = mmr.ReadMatrix("./TestData/Matrices/can24_pattern_symmetric_coordinate_24.mtx", StorageType.Dense);
            MatrixMarketWriter mmw = new MatrixMarketWriter(ExchangeFormat.Array, DataType.Real);

            using (TextWriter tw = new StreamWriter("./TestData/Matrices/temp_writer_pattern_symmetric_array.mtx"))
            {
                mmw.WriteMatrix(matrix, tw);
            }

            matrix = mmr.ReadMatrix("./TestData/Matrices/temp_writer_pattern_symmetric_array.mtx", StorageType.Dense);
            Assert.AreEqual(24, matrix.Rows);
            Assert.AreEqual(24, matrix.Columns);
        }


        [Test]
        public void WriteMatrixTextReaderPatternSymmetricArrayFormat()
        {
            MatrixMarketReader mmr = new MatrixMarketReader();
            Matrix matrix = mmr.ReadMatrix("./TestData/Matrices/can24_pattern_symmetric_coordinate_24.mtx", StorageType.Dense);
            MatrixMarketWriter mmw = new MatrixMarketWriter(ExchangeFormat.Array, DataType.Real);

            using (TextWriter tw = new StreamWriter("./TestData/Matrices/temp_writer_pattern_symmetric_array.mtx"))
            {
                mmw.WriteMatrix(matrix, tw, "E");
            }

            matrix = mmr.ReadMatrix("./TestData/Matrices/temp_writer_pattern_symmetric_array.mtx", StorageType.Dense);
            Assert.AreEqual(24, matrix.Rows);
            Assert.AreEqual(24, matrix.Columns);
        }
    }
}
